﻿using System;
using System.Collections.Generic;
using AdaptiveAgents.Agents.Choosers;
using AdaptiveAgents.Agents;
using AdaptiveAgents.Loggers;
using AdaptiveAgents.TeammateModels;

namespace AdaptiveAgents.Agents.Choosers
{
    class NewAdaptiveNextPlayerChooser : NextPlayerChooser
    {
        public NewAdaptiveNextPlayerChooser(Agent agent)
            : base(agent)
        {
            agent.NextPlayerChooser = this;
        }

        #region try2

        public override int choose(int nothing)
        {
            double[] data;
            double competence;
            double maxCompetence = double.MinValue;
            int myIndex = _me.Environment.agents.IndexOf(_me);
            double myCompetence = _me.Competence.Mean;
            bool unrealData = false;
            double[] epsilons = new double[3];
            double[] competences = new double[3];
            int currIndex;

            foreach (var agent in _me.Environment.agents)
            {
                currIndex = _me.Environment.agents.IndexOf(agent);
                if (agent.NumActions == 0)
                {
                    return currIndex;
                }
                
                data = _me.getTeammateModel(agent.ID).estimateEpsilonAndCometence1(_me.ObservationsSet.observations);
                epsilons[currIndex] = data[0];
                competences[currIndex] = data[1];
                if (maxCompetence < data[1])
                {
                    maxCompetence = data[1];
                }
                if (agent.Equals(_me))
                {
                    if (data[1] < 0.9 * myCompetence)
                    {
                        unrealData = true;
                    }
                }
            }
            if (unrealData)
            {
                double decreaseFactor = maxCompetence / myCompetence;
                double decisionEpsilon = _me.Epsilon / decreaseFactor;
                double rand = Generator.getNextDouble();
                if (rand < decisionEpsilon)
                {
                    return myIndex;
                }
            }
            return FindBestPlayer(epsilons, competences);
        }

        private int FindBestPlayer(double[] epsilons, double[] competences)
        {
            int[] competenceOrder = Order(competences);
            int[] epsilonOrder = Order(epsilons);

            if ((epsilons[epsilonOrder[0]] < 0.5) || (competences[competenceOrder[0]] - competences[competenceOrder[1]] > 0.2))
            {
                return competenceOrder[0];
            }

            if (competenceOrder[0] != epsilonOrder[0])
            {
                if ((competenceOrder[0] != epsilonOrder[1]) || (epsilons[epsilonOrder[0]] - epsilons[epsilonOrder[1]] < 0.1))
                {
                    return competenceOrder[0];
                }
                return competenceOrder[1];
            }
            else
            {
                return competenceOrder[1];
            }
        }

        private int[] Order(double[] array)
        {
            if (array[0] > array[1])
            {
                if (array[1] > array[2])
                {
                    return new int[3] { 0, 1, 2 };
                }
                else // 2 > 1
                {
                    if (array[0] > array[2])
                    {
                        return new int[3] { 0, 2, 1 };
                    }
                    else // 2 > 0
                    {
                        return new int[3] { 2, 0, 1 };
                    }
                }
            }
            else // 1 > 0
            {
                if (array[0] > array[2])
                {
                    return new int[3] { 1, 0, 2 };
                }
                else // 2 > 0
                {
                    if (array[1] > array[2])
                    {
                        return new int[3] { 1, 2, 0 };
                    }
                    else // 2 > 1
                    {
                        return new int[3] { 2, 1, 0 };
                    }
                }
            }
        }

        #endregion
    }

}
